<html>
  <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <meta name="theme-color" content="#008000"/>
   <title>planes_ml</title>
   <link rel="manifest" href="planes_ml_manifest.json">
   <script>
    if('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/planes_ml_sw.js')
        .then(function() {
          console.log('Service Worker Registered');
        });
    }
   </script>
    <style>
      body {
        margin: 0;
      }
    </style>
  </head>
  <body>
  <h1>planes_ml</h1>
  <script src="three.js"></script>
  <script src="GLTFLoader.js"></script>
  <script>
    let container, scene, camera, session, plantMeshes, planeMeshes;
    // let planeTracker = null;

    const localVector = new THREE.Vector3();
    const localVector2 = new THREE.Vector3();
    // const localQuaternion = new THREE.Quaternion();
    // const downToUpQuaterion = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, -1, 0), new THREE.Vector3(0, 1, 0));
    
    const _loadPlantMeshes = () => new Promise((accept, reject) => {
      const loader = new THREE.GLTFLoader();
      loader.load('plants.glb', o => {
        o = o.scene;

        const result = [];
        o.traverse(e => {
          if (e.isMesh) {
            e.frustumCulled = false;
            result.push(e);
          }
        });

        accept(result);
      });
    });

    planeMeshes = [];
    /* const planeGeometry1 = new THREE.PlaneBufferGeometry(1, 1)
    const planeMaterial1 = new THREE.MeshPhongMaterial({
      color: 0xe91e63,
    });
    const planeGeometry2 = planeGeometry1.clone()
      .applyMatrix(
        new THREE.Matrix4().makeRotationFromQuaternion(
          new THREE.Quaternion().setFromUnitVectors(
            new THREE.Vector3(0, 0, 1),
            new THREE.Vector3(0, 0, -1),
          )
        )
      );
    const planeMaterial2 = new THREE.MeshPhongMaterial({
      color: 0x673ab7,
    }); */
    /* const _loadPlanes = updates => {
      // _clearPlanes();

      for (let i = 0; i < updates.length; i++) {
        const update = updates[i];
        const {type, id, position, normal, scale} = update;

        if (type === 'new') {
          const planeMesh = new THREE.Object3D();
          planeMesh.position.fromArray(position);
          planeMesh.quaternion.setFromUnitVectors(
            localVector.set(0, 0, 1),
            localVector2.fromArray(normal)
          );
          planeMesh.scale.fromArray(scale);
          planeMesh.planeId = id;

          const plantMesh = (() => {
            const index = Math.floor(Math.random() * plantMeshes.length);
            const plantMesh = plantMeshes[index];
            return plantMesh.clone();
          })();
          planeMesh.add(plantMesh);

          scene.add(planeMesh);
          planeMeshes.push(planeMesh);
        } else {
          const index = planeMeshes.findIndex(planeMesh => planeMesh.planeId === id);
          if (index !== -1) {
            const planeMesh = planeMeshes[index];
            scene.remove(planeMesh);
            planeMeshes.splice(index, 1);
          }
        }
      }
    }; */
    /* const _clearPlanes = () => {
      for (let i = 0; i < planeMeshes.length; i++) {
        const planeMesh = planeMeshes[i];
        scene.remove(planeMesh);
      }
      planeMeshes.length = 0;
    }; */
    /* const _onPlanes = e => {
      const {updates} = e;
      _loadPlanes(updates);
    }; */
    const _planeadd = e => {
      const {type, id, position, normal, size} = e.update;
      console.log('plane add', id);

      const planeMesh = new THREE.Object3D();
      planeMesh.position.fromArray(position);
      planeMesh.quaternion.setFromUnitVectors(
        localVector.set(0, 0, 1),
        localVector2.fromArray(normal)
      );
      // planeMesh.scale.set(size[0], size[1], 1);
      planeMesh.planeId = id;

      const plantMesh = (() => {
        const index = Math.floor(Math.random() * plantMeshes.length);
        const plantMesh = plantMeshes[index];
        return plantMesh.clone();
      })();
      planeMesh.add(plantMesh);

      scene.add(planeMesh);
      planeMeshes.push(planeMesh);
    };
    const _planeupdate = e => {
      console.log('plane update', e.update.id);

      const planeMesh = planeMeshes.find(planeMesh => planeMesh.planeId === e.update.id);
      if (planeMesh) {
      const {position, normal, size} = e.update;
        planeMesh.position.fromArray(position);
        planeMesh.quaternion.setFromUnitVectors(
          localVector.set(0, 0, 1),
          localVector2.fromArray(normal)
        );
        // planeMesh.scale.set(size[0], size[1], 1);
      }
    };
    const _planeremove = e => {
      console.log('plane remove', e.update.id);

      const index = planeMeshes.findIndex(planeMesh => planeMesh.planeId === e.update.id);
      if (index !== -1) {
        const planeMesh = planeMeshes[index];
        scene.remove(planeMesh);
        planeMeshes.splice(index, 1);
      }
    };

    async function init() {
      container = document.createElement('div');
      document.body.appendChild(container);

      scene = new THREE.Scene();
      scene.matrixAutoUpdate = false;
      // scene.background = new THREE.Color(0x3B3961);

      camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
      // camera.position.set(0, 1, 0);
      camera.lookAt(new THREE.Vector3());
      scene.add(camera);

      const ambientLight = new THREE.AmbientLight(0x808080);
      scene.add(ambientLight);

      const directionalLight = new THREE.DirectionalLight(0xFFFFFF, 1);
      directionalLight.position.set(1, 1, 1);
      scene.add(directionalLight);

      renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true,
      });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);

      // window.browser.magicleap.RequestDepthPopulation(true);
      // renderer.autoClear = false;

      container.appendChild(renderer.domElement);

      renderer.setAnimationLoop(animate);
    }

    function animate(time, frame) {
      /* if (model) {
        const animationTime = 4000;
        const f = ((Date.now() % animationTime) / animationTime) * (Math.PI * 2);
        model.quaternion.setFromUnitVectors(
          new THREE.Vector3(0, 0, 1),
          new THREE.Vector3(Math.cos(f), 0, Math.sin(f)).normalize()
        );
        model.updateMatrixWorld();
      } */
      /* if (planeMeshes.length) {
        const vrCamera = renderer.vr.enabled ? renderer.vr.getCamera(camera).cameras[0] : camera;
        vrCamera.matrixWorld.decompose(localVector, localQuaternion, localVector2);
        for (let i = 0; i < planeMeshes.length; i++) {
          const planeMesh = planeMeshes[i];
          const factor = Math.min(Math.max(planeMesh.position.distanceTo(localVector), 0), 3)/3;
          const scaleFactor = 1 - factor;
          if (scaleFactor > 0) {
            planeMesh.scale.set(scaleFactor, scaleFactor, scaleFactor);
            planeMesh.updateMatrixWorld();
            planeMesh.visible = true;
          } else {
            planeMesh.visible = false;
          }
        }
      } */

      renderer.render(scene, renderer.vr.enabled ? renderer.vr.getCamera(camera) : camera);
    }

    (async () => {
      await init();

      // console.log('request session');
      session = await navigator.xr.requestSession({
        exclusive: true,
        extensions: {
          planeTracking: true,
        },
      }).catch(err => Promise.resolve(null));

      if (session) {
        // console.log('request first frame');
        session.requestAnimationFrame((timestamp, frame) => {
          renderer.vr.setSession(session, {
            frameOfReferenceType: 'stage',
          });

          const {views} = frame.getViewerPose();
          const viewport = session.baseLayer.getViewport(views[0]);
          const width = viewport.width;
          const height = viewport.height;

          renderer.setSize(width * 2, height);

          renderer.setAnimationLoop(null);

          renderer.vr.enabled = true;
          renderer.vr.setAnimationLoop(animate);
          
          _loadPlantMeshes()
            .then(newPlantMeshes => {
              plantMeshes = newPlantMeshes;

              session.addEventListener('planeadd', _planeadd);
              session.addEventListener('planeremove', _planeremove);
              /* planeTracker = session.requestPlaneTracking();
              planeTracker.onplanes = _onPlanes; */
            })
            .catch(err => {
              console.warn(err.stack);
            });
            
          console.log('running!');
        });
      } else {
        console.log('no xr devices');
      }
    })();
  </script>
  </body>
</html>
